/*
 *   Copyright 2023 <a href="mailto:asialjim@hotmail.com">Asial Jim</a>
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.asialjim.encommunicate.base.rsa;

import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * 基于 RSA 签名工具
 *
 * @author Copyright © <a href="mailto:asialjim@hotmail.com">Asial Jim</a>   Co., LTD
 * @version 1.0
 * @since 2023/2/24, &nbsp;&nbsp; <em>version:1.0</em>, &nbsp;&nbsp; <em>java version:17</em>
 */
@SuppressWarnings("unused")
public interface RSASigner {

    /**
     * 签名
	 * @param source {@link String 待签名内容}
     * @return {@link String 签名内容}
     * @since 2023/2/24
     */
    String sign(String source);

    /**
     * 签名
     * @param source {@link java.lang.reflect.Array 待签名内容}
     * @return {@link String 签名内容}
     * @since 2023/2/24
     */
    String sign(byte[] source);

    /**
     * 验签
	 * @param source {@link String 原待验签内容}
	 * @param signature {@link String 待验签签名}
     * @return {@link Boolean 验签结果}
     * @since 2023/2/24
     */
    boolean checkSign(String source, String signature);

    /**
     * 验签
     * @param source {@link String 原待验签内容}
     * @param signature {@link String 待验签签名}
     * @return {@link Boolean 验签结果}
     * @since 2023/2/24
     */
    boolean checkSign(byte[] source, String signature);

    boolean checkSign(InputStream inputStream, String signature);

    default String sign(String source, String priKey) {
        return sign(source.getBytes(), priKey);
    }

    default String sign(byte[] source, String priKey) {
        try {
            byte[] privateKeyBytes = Base64.getDecoder().decode(priKey);
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSAKeyPairProperty.keyAlgorithm());
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            Signature sign = Signature.getInstance(RSAKeyPairProperty.signAlgorithm());
            sign.initSign(privateKey);
            sign.update(source);
            byte[] signed = sign.sign();

            return Base64.getEncoder().encodeToString(signed);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    default boolean checkSign(String source, String pubKey, String signature) {
        return checkSign(source.getBytes(), pubKey, signature);
    }

    default boolean checkSign(byte[] source, String pubKey, String signature){
        boolean verifySignSuccess = false;
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(pubKey);
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSAKeyPairProperty.keyAlgorithm());
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            Signature verifySign = Signature.getInstance(RSAKeyPairProperty.signAlgorithm());
            verifySign.initVerify(publicKey);
            verifySign.update(source);

            verifySignSuccess = verifySign.verify(Base64.getDecoder().decode(signature));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return verifySignSuccess;
    }
}